/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package za.co.pas.business.abstracts;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
import java.util.ArrayList;
import org.apache.log4j.Logger;

/**
 * This is the observable
 * @author alabuschagne
 */
public class AbstractController implements PropertyChangeListener
{

    private ArrayList<AbstractView> registeredViews;
    private ArrayList<AbstractDataModel> registeredModels;
    private static Logger logger = Logger.getLogger(AbstractController.class);

    public AbstractController()
    {
        registeredViews = new ArrayList<AbstractView>();
        registeredModels = new ArrayList<AbstractDataModel>();
    }

    public void addModel(AbstractDataModel model) throws NullPointerException
    {
        if (model == null)
        {
            throw new NullPointerException("model is null");
        }
        registeredModels.add(model);
        model.addPropertyChangeListener(this);
    }

    public void removeModel(AbstractDataModel model)
    {
        registeredModels.remove(model);
        model.removePropertyChangeListener(this);
    }

    public void addView(AbstractView view) throws NullPointerException
    {
        if (view == null)
        {
            throw new NullPointerException("view is null");
        }
        registeredViews.add(view);
    }

    public void removeView(AbstractView view)
    {
        registeredViews.remove(view);
    }

    //  Use this to observe property changes from registered models
    //  and propagate them on to all the views.
    @Override
    public void propertyChange(PropertyChangeEvent evt)
    {

        for (AbstractView view : registeredViews)
        {
            view.modelPropertyChange(evt);
        }
    }

    protected void setModelProperty(String propertyName, Object newValue)
    {
        setModelProperty(propertyName, newValue, null);
    }
    /**
     * This is a convenience method that subclasses can call upon
     * to fire property changes back to the models. This method
     * uses reflection to inspect each of the model classes
     * to determine whether it is the owner of the property
     * in question. If it isn't, a NoSuchMethodException is thrown,
     * which the method ignores.
     *
     * @param propertyName = The name of the property.
     * @param newValue = An object that represents the new value
     * of the property.
     */
    protected void setModelProperty(String propertyName, Object newValue, Object extra)
    {

        for (AbstractDataModel model : registeredModels)
        {
            try
            {
                Method method;
                if (extra == null)
                {
                    logger.info("set" + propertyName);
                    logger.info("newValue class name: " + newValue.getClass().getName());
                    method = model.getClass().getMethod("set" + propertyName, new Class[]
                            {
                                newValue.getClass()
                            });
                    method.invoke(model, newValue);
                }
                else
                {
                    logger.info("set" + propertyName);
                    logger.info("newValue class name: " + newValue.getClass().getName());
                    logger.info("extra class name: " + extra.getClass().getName());
                    method = model.getClass().getMethod("set" + propertyName, new Class[]
                            {
                                newValue.getClass(), extra.getClass()
                            });
                    method.invoke(model, newValue, extra);
                }
            }
            catch (Exception ex)
            {
                //Skipping this
                logger.error(ex.getMessage(), ex);
            }
        }
    }
}
